Skip to content

3.1 AppStartup 启动

3.1.1 Startup

Startup 类是 ASP.NET Core 应用程序启动默认调用的类,该类是在 Program.cs 中配置:

.NET5 方式

Furion.Web.Entry\Program.cs

using Microsoft.AspNetCore.Hosting;  
using Microsoft.Extensions.Hosting;  

namespace Furion.Web.Entry  
{  
    public class Program  
    {  
        public static void Main(string[] args)  
        {  
            CreateHostBuilder(args).Build().Run();  
        }  

        public static IHostBuilder CreateHostBuilder(string[] args)  
        {  
            return Host.CreateDefaultBuilder(args)  
                .ConfigureWebHostDefaults(webBuilder =>  
                {  
                    webBuilder.UseStartup<Startup>();  
                });  
        }  
    }  
}  

.NET6 方式

.NET6 中微软已不再推荐 UseStartup<TStarup>() 方式。

3.1.1.1 Startup 两个重要方法

Startup 默认有两个重要的方法:

  • ConfigureServices:配置应用所需服务,在该方法中可以添加应用所需要的功能或服务
  • Configure:配置应用请求处理管道

默认代码如下:

Furion.Web.Entry\Startup.cs

using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.Extensions.DependencyInjection;  

namespace Furion.Web.Entry  
{  
    public class Startup  
    {  
        public void ConfigureServices(IServiceCollection services)  
        {  
        }  

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
        }  
    }  
}  

在这里,不打算详细讲 Startup 类的具体功能和作用。

了解更多想了解更多 Startup 知识可查阅 ASP.NET Core - Startup 类 章节。

3.1.2 AppStartup

Furion 框架中,提供了更为灵活的 Startup 类配置方式,无需在 Web 启用层 中配置,可将配置放到任何项目层。

可能会有读者有疑问,为什么要多此一举呢?原因有几点:

  • Startup 类默认和 Web 应用层 绑定在一起,这样就会导致如果我创建了新的 Web 应用层Startup 又要重新配置
  • 随着业务的增长,需要集成越来越多的第三方服务,这时候 Startup 类就会变得越来越臃肿,难以维护
  • Startup 类无法与其他项目类型进行共用

所以,Furion 提供了更加灵活的配置方式:AppStartup

注意事项如果 AppStartup 的派生类所在的项目层没有被启动层直接或间接添加引用,那么这个 Startup.cs 就会被忽略,也就是不会自动载入注册。

3.1.2.1 如何配置 AppStartup

AppStartup 是一个抽象的空类,没有任何定义成员。正是因为这样,才提供更加灵活的配置方式。

3.1.2.2 AppStartup 约定

AppStartup 派生类只有两个小约定:

  • 任何公开、非静态、返回值为 void 且方法第一个参数是 IServiceCollection 类型,那么他就是一个 ConfigureServices 方法
  • 任何公开、非静态、返回值为 void 且方法第一个参数是 IApplicationBuilder 类型,第二个参数是 IWebHostEnvironment 类型,那么他就是一个 Configure 方法

所以,我们可以自由的编写方法,只要遵循约定即可,如:

using Microsoft.Extensions.DependencyInjection;  

namespace Furion.EntityFramework.Core  
{  
    public class MyStartup : AppStartup  
    {  
        public void ConfigureServices(IServiceCollection services)  
        {  
            services.AddDataValidation();  
        }  

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
            app.UseSwagger();  
        }  

        // 可以随意定义名字和方法  
        public void XXXXName(IServiceCollection services)  
        {  
        }  

        // 可以随意定义名字和方法  
        public void ZZZName(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
        }  
    }  
}  

3.1.2.3 AppStartup 配置顺序

默认情况下,AppStartup 配置顺序由所在程序集的名称进行正序调用,如果我们需要配置执行顺序,只需要在 AppStartup 派生类中贴 [AppStartup(order)] 特性即可。

order 数值越大,越在前面调用,如:

using Microsoft.Extensions.DependencyInjection;  

namespace Furion.EntityFramework.Core  
{  
    [AppStartup(10)]  
    public class FirstStartup : AppStartup  
    {  
        public void ConfigureServices(IServiceCollection services)  
        {  
        }  

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
        }  
    }  
}  

using Microsoft.Extensions.DependencyInjection;  

namespace Furion.EntityFramework.Core  
{  
    [AppStartup(9)]  
    public class SecondStartup : AppStartup  
    {  
        public void ConfigureServices(IServiceCollection services)  
        {  
        }  

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
        }  
    }  
}  

FirstStartup 会在 SecondStartup 之前调用。

3.1.2.4 AppStartup 方法调用顺序

AppStartup 方法调用顺序和方法的书写先后有关,越在前面的方法越先调用。

3.1.3 Startup 配置最佳实践

v3.6.3+ 说明在 Furion v3.6.3+ 版本之后无需创建空 Startup.cs 类,内部已实现 FakeStartup 模式。

建议 Web 启动层的 Startup.cs 保持为空方法体,如:

Furion.Web.Entry\Startup.cs

using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.Extensions.DependencyInjection;  

namespace Furion.Web.Entry  
{  
    public class Startup  
    {  
        public void ConfigureServices(IServiceCollection services)  
        {  
        }  

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
        }  
    }  
}  

将所有 Web 应用层 配置迁移到 Furion.Web.Core.Startup.cs 中,如:

Furion.Web.Core\Startup.cs

using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Hosting;  

namespace Furion.Web.Core  
{  
    public sealed class FurWebCoreStartup : AppStartup  
    {  
        public void ConfigureServices(IServiceCollection services)  
        {  
            services.AddCorsAccessor();  

            services.AddControllers().AddInject();  
        }  

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
        {  
            if (env.IsDevelopment())  
            {  
                app.UseDeveloperExceptionPage();  
            }  

            app.UseHttpsRedirection();  

            app.UseRouting();  

            app.UseCorsAccessor();  

            app.UseAuthentication();  
            app.UseAuthorization();  

            app.UseInject();  

            app.UseEndpoints(endpoints =>  
            {  
                endpoints.MapControllers();  
            });  
        }  
    }  
}  

这样,后续更换 Web 应用层 也无需重新配置 Startup.cs

3.1.4 构造函数注入说明

AppStartup 的派生类并未提供依赖注入的功能,也即是无法通过构造函数进行注入服务。原因是 AppStartup 是个空类,目的是用来查找 Startup 的。

那如何像 Startup.cs 一样使用服务呢?

  • 获取配置 IConfiguration 实例:通过 App.Configuration
  • 解析服务:通过 App.GetService<TService>()app.ApplicationServices.GetService<TService>()

关于 Configure 方法注入AppStartup 针对 Configure 方法提供了参数解析注入功能,也就是只要在方法中声明接口参数即可自动注入,如:

// app 和 env 会自动注入  
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
{  
}  

3.1.5 关于 appsettings.json

在默认情况下,ASP.NET Core 配置放在 appsettings.json 中配置,但是这样的方式和 Startup.cs 配置一样的道理,一旦我们更换了 Web 应用层,那么 appsettings.json 又要重新配置一次。

所以,Furion 框架提供了更加灵活的方式配置 appsettings.json只需要在任何项目层根目录下创建 .json 文件即可。Furion 框架最后会自动合并所有分散的配置文件。

如我们在 Furion.EntityFramework.Core 层创建 dbsettings.json 配置数据库连接字符串,如:

Furion.EntityFramework.Core\dbsettings.json

{  
  "ConnectionStrings": {  
    "DbConnectionString": "Server=localhost;Database=Furion;User=sa;Password=000000;MultipleActiveResultSets=True;",  
    "Sqlite3ConnectionString": "Data Source=./Furion.db"  
  }  
}  

无需在 appsettings.json 中配置,下面是 appsettings.json 默认代码:

{  
  "Logging": {  
    "LogLevel": {  
      "Default": "Information",  
      "Microsoft": "Warning",  
      "Microsoft.Hosting.Lifetime": "Information",  
      "Microsoft.EntityFrameworkCore": "Information"  
    }  
  },  
  "AllowedHosts": "*"  
}  

这样我们把配置文件分散在不同项目层之后,就可以实现共用和共享了。

特别注意其他层的配置文件不能以 appsettings.json 命名,会导致覆盖启动层的配置。

另外,在其他层创建的 *.json 文件必须设置文件属性为 始终复制或较新复制

3.1.6 WebApplication 对象配置

ASP.NET 6 开始,中间件注册方式由过去的 IApplicationBuilder 接口类型替换成了 WebApplication 类型,如需在 AppStartup 中使用 WebApplication 类型,只需要在 app.UseEndpoints(builder =>{}) 中使用即可,如:

ASP.NET 6+ 使用状况检查:

var builder = WebApplication.CreateBuilder(args);  
builder.Services.AddHealthChecks();  

var app = builder.Build();  
app.MapHealthChecks("/healthz");  

app.Run();  

AppStartup 中的 Configure 中使用:

app.UseEndpoints(builder =>  
{  
    builder.MapHealthChecks("/healthz");    // 状况(健康)检查  
});  

3.1.7 反馈与建议

与我们交流给 Furion 提 Issue